/**
 * @(#)SystemLogAspect.java 2017年1月17日
 * Copyright(C) 2015 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.annotation;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.shiro.web.servlet.ShiroHttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jsbd.boss.common.ConstantsCmp;
import org.jsbd.boss.dao.IUserOptLogDAO;
import org.jsbd.boss.domian.User;
import org.jsbd.boss.domian.UserOptLog;
import org.jsbd.boss.domian.channel.ChannelApkConfig;
import org.jsbd.boss.domian.channel.RetentFilterConfig;
import org.jsbd.boss.service.IChannelApkInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

/**
 * TODO 请加入本类的说明
 * 
 * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
 * @version 1.0.0
 */
@Aspect
public class SystemLogAspect {
	public static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);

	@Autowired
	private IUserOptLogDAO userOptLogDAO;
	@Resource
	private IChannelApkInfoService channelApkService;

	// Controller层切点
	@Pointcut("@annotation(org.jsbd.boss.annotation.SystemControllerLog)")
	public void controllerAspect() {
	}

	// Service层切点
	@Pointcut("@annotation(org.jsbd.boss.annotation.SystemControllerLog)")
	public void serviceAspect() {
	}

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		HttpSession session = request.getSession();
		// 读取session中的用户
		User user = (User) session.getAttribute(ConstantsCmp.USER_SESSION_INFO);
		// 请求的IP
		String ip = request.getRemoteAddr();
		String params = "";

		try {
			for (Object arg : joinPoint.getArgs()) {
				if (arg instanceof ShiroHttpServletResponse) {
					continue;
				} else if (arg instanceof String||arg instanceof String[] ) {
					params += "String:"+arg.toString()+";";
				} else if (arg instanceof MultipartFile[]) {
					int i = 0;
					for (MultipartFile file : (MultipartFile[]) arg) {
						i++;
						if (file.getSize() == 0) {
							continue;
						} else {
							params += "file" + i + ":" + file.getOriginalFilename()+";";
						}

					}
				} else if (arg instanceof ChannelApkConfig) {
					ChannelApkConfig newapkconfig = (ChannelApkConfig) arg;
					if (newapkconfig.getMark() == null) {
						params += ToStringBuilder.reflectionToString(arg);
					} else {
						ChannelApkConfig oldapkconfig = channelApkService.selectApkConfig(newapkconfig.getMark());
						Map<String, String> result = compare(newapkconfig, oldapkconfig);
						params += "mark:" + newapkconfig.getMark() + ";" + result.toString();
					}
				} else if (arg instanceof RetentFilterConfig) {
					RetentFilterConfig newconfig = (RetentFilterConfig) arg;
					ChannelApkConfig apkconfig = channelApkService.selectApkConfigByid(newconfig.getApkId());
					params += "mark:" + apkconfig.getMark() + ";" + ToStringBuilder.reflectionToString(arg);
				} else {
					params += ToStringBuilder.reflectionToString(arg);
				}

			}
			UserOptLog userOptLog = new UserOptLog();
			userOptLog.setDescription(getControllerMethodDescription(joinPoint));
			userOptLog.setIp(ip);
			userOptLog.setParams(params);
			if (user != null) {
				userOptLog.setName(user.getNickname());
			} else {
				userOptLog.setName("-1");
			}
			userOptLogDAO.insert(userOptLog);
			// 保存数据库
			logger.info("=====前置通知结束=====");
		} catch (Exception e) {
			// 记录本地异常日志
			logger.error("==前置通知异常==");
			logger.error("异常信息:{}", e.getMessage());
		}
	}

	/**
	 * 异常通知 用于拦截service层记录异常日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		HttpSession session = request.getSession();
		// 读取session中的用户
		User user = (User) session.getAttribute(ConstantsCmp.USER_SESSION_INFO);
		// 获取请求ip
		String ip = request.getRemoteAddr();
		// 获取用户请求方法的参数并序列化为JSON格式字符串
		String params = "";
		if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
			for (int i = 0; i < joinPoint.getArgs().length; i++) {
				// params += JSONUtil.toJsonString(joinPoint.getArgs()[i]) +
				// ";";
			}
		}
		try {
			/* ========控制台输出========= */
			logger.info("=====异常通知开始=====");
			logger.info("异常代码:" + e.getClass().getName());
			logger.info("异常信息:" + e.getMessage());
			logger.info("异常方法:"
					+ (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
			logger.info("方法描述:" + getServiceMthodDescription(joinPoint));
			logger.info("请求人:" + user.getNickname());
			logger.info("请求IP:" + ip);
			logger.info("请求参数:" + params);
			/* ==========数据库日志========= */
			// 保存数据库
			logger.info("=====异常通知结束=====");
		} catch (Exception ex) {
			// 记录本地异常日志
			logger.error("==异常通知异常==");
			logger.error("异常信息:{}", ex.getMessage());
		}
		/* ==========记录本地异常日志========== */
		// logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}",
		// joinPoint.getTarget().getClass().getName() +
		// joinPoint.getSignature().getName(), e.getClass().getName(),
		// e.getMessage(), params);

	}

	/**
	 * 获取注解中对方法的描述信息 用于service层注解
	 * 
	 * @param joinPoint
	 *            切点
	 * @return 方法描述
	 * @throws Exception
	 */
	public static String getServiceMthodDescription(JoinPoint joinPoint) throws Exception {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method m = signature.getMethod();
		String description = m.getAnnotation(SystemControllerLog.class).description();
		return description;
	}

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint
	 *            切点
	 * @return 方法描述
	 * @throws Exception
	 */
	public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method m = signature.getMethod();
		String description = m.getAnnotation(SystemControllerLog.class).description();
		return description;
	}

	public static <T> Map<String, String> compare(T obj1, T Obj2) throws Exception {

		Map<String, String> result = new HashMap<String, String>();

		Field[] fs = obj1.getClass().getDeclaredFields();
		for (Field f : fs) {
			f.setAccessible(true);
			Object v1 = f.get(obj1);
			Object v2 = f.get(Obj2);
			if (!equals(v1, v2)) {
				result.put(f.getName(), String.valueOf("new:" + v1 + " old:" + v2));
			}
		}
		return result;
	}

	public static boolean equals(Object obj1, Object obj2) {

		if (obj1 == obj2) {
			return true;
		}
		if (obj1 == null || obj2 == null) {
			return true;
		}
		return obj1.equals(obj2);
	}

}
